#!/bin/bash

PATCH=$1

raw_ver=$(uname -r | sed 's/\.x86_64//')
ver=$(echo ${raw_ver} | grep -Eo 'jd_[0-9]+.*$')
dist=$(uname -r | grep -Eo 'el.')

# patches for each kernel verison
of_4_18_0_80_el8=("tty_4_18_0_80_el8")
of_4_18_0_80_11_2_el8_0=("tty_4-18-0-80-11-2-el8_0")
of_4_18_0_147_5_1_el8_1=("oom_GFP_NOFS" "tty_4-18-0-147-5-1-el8_1")
of_4_18_0_193_el8=("tty_4-18-0-193-el8")
of_4_18_0_193_14_2_el8_2=("tty_4-18-0-193-14-2-el8_2")
jd_001=("jd_001_icmp_hotfix" "tty_4-18-0-193-el8-jd_001")
jd_004=("tty_4-18-0-193-el8-jd_004" "jd_004_fix_blkcg_hardlockup" "jd_004_icmp_hotfix")
jd_008=("tty_4-18-0-193-el8-jd_008" "jd_008_fix_blkcg_hardlockup" "jd_008_icmp_hotfix")
jd_009=("tty_4-18-0-193-el8-jd_009" "jd_009_fix_blkcg_hardlockup" "jd_009_icmp_hotfix")
jd_016=("jd_016_fix_blkcg_hardlockup" "jd_016_icmp_hotfix" "jd_016_fix_quick_ack_issue")
jd_017=("jd_017_fix_blkcg_hardlockup" "jd_017_icmp_hotfix" "jd_017_fix_quick_ack_issue")
jd_018=("jd_018_fix_blkcg_hardlockup" "jd_018_icmp_hotfix" "jd_018_fix_quick_ack_issue")
jd_020=("jd_020_fix_blkcg_hardlockup" "jd_020_icmp_hotfix")
jd_025=("jd_025_fix_blkcg_hardlockup" "jd_025_icmp_hotfix")
jd_029=("jd_029_fix_blkcg_hardlockup")
jd_030=("jd_030_fix_blkcg_hardlockup")
jd_023_offline=("jd_023_offline_fix_blkcg_hardlockup" "jd_023_offline_icmp_hotfix")

get_patches()
{
    local version=$1
    case $version in
    "jd_001")
        echo ${jd_001[@]}
	;;
    "jd_004")
        echo ${jd_004[@]}
	;;
    "jd_008")
        echo ${jd_008[@]}
	;;
    "jd_009")
        echo ${jd_009[@]}
	;;
    "jd_016")
        echo ${jd_016[@]}
	;;
    "jd_017")
        echo ${jd_017[@]}
	;;
    "jd_018")
        echo ${jd_018[@]}
	;;
    "jd_020")
        echo ${jd_020[@]}
	;;
    "jd_025")
        echo ${jd_025[@]}
	;;
    "jd_029")
        echo ${jd_029[@]}
	;;
    "jd_030")
        echo ${jd_030[@]}
	;;
    "jd_023_offline")
        echo ${jd_023_offline[@]}
	;;
    "4_18_0_80_el8")
        echo ${of_4_18_0_80_el8[@]}
        ;;
    "4_18_0_80_11_2_el8_0")
        echo ${of_4_18_0_80_11_2_el8_0[@]}
        ;;
    "4_18_0_147_5_1_el8_1")
	echo ${of_4_18_0_147_5_1_el8_1[@]}
        ;;
    "4_18_0_193_el8")
	echo ${of_4_18_0_193_el8[@]}
        ;;
    "4_18_0_193_14_2_el8_2")
	echo ${of_4_18_0_193_14_2_el8_2[@]}
	;;
    esac
}

function do_install()
{
    local name=$1
    local kname=$(echo $name | sed -e 's/\./_/g' -e 's/-/_/g')
    local pat=livepatch_${kname}
    local url=http://storage.jd.local/k8s-node/kernel/hotfix/livepatch-${name}.ko
    echo "install patch ${pat}"
    set -e
    DIR=$(mktemp -d)
    wget -nv -P $DIR $url

    set +e
    kpatch uninstall ${pat}
    set -e
    kpatch install $DIR/$(basename ${url})
    kpatch load $pat
    rm -rf $DIR
    set +e
}

function fix_kpatch()
{
    local ver=$1
    local INST=$(mktemp)
    kpatch list | grep -E '\(.*\)$' | grep ${ver} | awk '{print $1}' > ${INST}
    local LOAD=$(mktemp)
    kpatch list | grep -E '\[enabled\]$' | awk '{print $1}'  > ${LOAD}

    INUM=$(wc -l ${INST} | awk '{print $1}')
    LNUM=$(wc -l ${LOAD} | awk '{print $1}')

    # remove some uninstalled patch
    if [ ${LNUM} -gt ${INUM} ]; then
        while read p
        do
            grep -q ${p} ${INST}
            if [ $? -ne 0 ]; then
                echo Y | kpatch unload ${p}
            fi
        done < ${LOAD}
        return
    fi

    while read p
    do
        grep -q ${p} ${LOAD}
        if [ $? -ne 0 ]; then
            lsmod | grep -q ${p}
	    if [ $? -eq 0 ]; then
                rmmod ${p}
            fi
            echo "reloading ${p}"
            kpatch load ${p}
        fi
    done < ${INST}

    rm -rf ${INST}
    rm -rf ${LOAD}
}

function check_install()
{
    local ver=$(uname -r | sed 's/\.x86_64//')
    INST=$(kpatch list | grep -E '\(.*\)$' | grep ${ver} -c)
    LOAD=$(kpatch list | grep -E '\[enabled\]$' -c)

    [ ${INST} -ne ${LOAD} ] && return 0
    return 1
}

function install_kpatch()
{
    local name=$1
    local kname=$(echo $name | sed -e 's/\./_/g' -e 's/-/_/g')
    local pat=livepatch_${kname}

    KO=$(lsmod | grep "${pat}")

    if [ -n "${KO}" ]; then
	echo "patch ${name} exists, check function ..."
	U=$(echo ${KO} | awk '{print $3}')
        if [ "${U}" -eq 0 ]; then
            echo "reinstall ..."
	    set -e
	    rmmod ${pat}
	    set +e
            do_install ${name}
        else
            echo "patch is ok, skip."
	fi
    else
        do_install ${name}
    fi

    if check_install; then
            fix_kpatch ${raw_ver}
            if check_install; then
                echo "Something Wrong, please fix !!"
                exit 1
            fi
    fi
    echo "everything is ok, done"
}

# user specified patch
if [ -n "$PATCH" ]; then
    set -x
    echo "install ${ver}_${PATCH}"
    install_kpatch ${ver}_${PATCH}
    set +x
else
    # our jdos kernel ?
    patches=""
    if [ "${raw_ver}" == "4.18.0-193.${dist}.${ver}" ]; then
	echo "target: jdos kernel ($(uname -r))"
        patches=$(get_patches $ver)
    else
        echo "target: centos offical kernel ($(uname -r))"
	ver=$(echo $raw_ver | sed -e 's/\./_/g' -e 's/-/_/g')
	patches=$(get_patches ${ver})
    fi

    if [ -z "$patches" ]; then
        echo "no live patche for kernel: $(uname -r)"
        echo "done"
        exit 0
    fi

    for p in $patches
    do
        if [ $dist = "el7" ]; then
	    p="el7_$p"
	    echo "update kpatch for centos 7"
            rpm -Uvh http://mirrors.jd.com/centos/7/os/x86_64/Packages/kpatch-0.6.1-6.el7.noarch.rpm
        fi
        install_kpatch $p
    done
fi

exit 0
